package com.imyuanma.qingyun.common.config.filter;

import com.imyuanma.qingyun.common.client.monitor.trace.TraceContext;
import com.imyuanma.qingyun.common.util.ClientInfoUtil;
import com.imyuanma.qingyun.common.util.StringUtil;
import com.imyuanma.qingyun.common.util.UuidUtil;
import com.imyuanma.qingyun.common.util.constants.CommonConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 全链路追踪过滤器
 *
 * @author wangjy
 * @date 2022/07/24 14:08:00
 */
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@WebFilter(urlPatterns = "/*")
public class TraceFilter extends OncePerRequestFilter {
    private static final Logger logger = LoggerFactory.getLogger(TraceFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String traceId = TraceContext.getTraceId();
        if (StringUtil.isBlank(traceId)) {
            // 参数形式传入traceId
            traceId = request.getParameter(CommonConstants.TRACE_KEY);
            if (StringUtil.isBlank(traceId)) {
                // 请求头方式传入traceId
                traceId = request.getHeader(CommonConstants.TRACE_KEY);
            }
            if (StringUtil.isBlank(traceId)) {
                // 使用uuid作为traceId
                traceId = UuidUtil.getUUID();
            }
            // 设置MDC,日志打印时输出,方便跟踪请求
            TraceContext.init(traceId);
            // 设置MDC,请求入口打印
            MDC.put(CommonConstants.MDC_KEY_ENTRANCE, request.getRequestURI());
            // 写入响应头
            response.setHeader(CommonConstants.TRACE_KEY, traceId);
            logger.info("[TraceFilter] URI={},客户端IP={},初始化链路ID={}", request.getRequestURI(), ClientInfoUtil.getClientIpAddr(request), traceId);
            try {
                filterChain.doFilter(request, response);
            } finally {
                // 清除
                TraceContext.clear();
                MDC.remove(CommonConstants.MDC_KEY_ENTRANCE);
            }
        } else {
            logger.debug("[TraceFilter] 当前请求已有traceId:{}", traceId);
            filterChain.doFilter(request, response);
        }
    }
}
